package com.zhang.discount.service.impl;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zhang.common.util.time.TimeUtils;
import com.zhang.discount.dto.SkuFlashSaleSearchDTO;
import com.zhang.discount.entity.FlashSales;
import com.zhang.discount.mapper.FlashSaleSkuMapper;
import com.zhang.discount.entity.FlashSaleSku;
import com.zhang.discount.service.FlashSaleSkuService;
import com.zhang.discount.service.FlashSalesService;
import com.zhang.discount.to.FlashSaleSkuModel;
import com.zhang.discount.vo.FlashSaleSkuInfoVO;
import io.swagger.models.auth.In;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import lombok.extern.slf4j.Slf4j;

import java.math.BigDecimal;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author 创世神
 * @since 2024-09-28 10:03:22
 */
@Service
@Slf4j
public class FlashSaleSkuServiceImpl extends ServiceImpl<FlashSaleSkuMapper, FlashSaleSku> implements FlashSaleSkuService {

    private final String SESSION_PREFIX = "flashSku:sessions:";
    private final String SKU_PREFIX = "flashSku:skus:";
    @Autowired
    private FlashSaleSkuMapper flashSaleSkuMapper;
    @Autowired
    private FlashSalesService flashSalesService;
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Override
    public Page<FlashSaleSku> findPage(SkuFlashSaleSearchDTO dto) {
        Page<FlashSaleSku> page = new Page<>(dto.getPageNum(), dto.getPageSize());
        LambdaQueryWrapper<FlashSaleSku> query = Wrappers.lambdaQuery(FlashSaleSku.class);
        if (!StrUtil.isBlank(dto.getSearchValue())) {
            query.or().eq(FlashSaleSku::getId, dto.getSearchValue())
                    .or().eq(FlashSaleSku::getSessionId, dto.getSearchValue())
                    .or().eq(FlashSaleSku::getSkuId, dto.getSearchValue());

        }
        if (!StrUtil.isBlank(dto.getSessionId())) {
            query.eq(FlashSaleSku::getSessionId, dto.getSessionId());
        }

        query.orderBy(true, true, FlashSaleSku::getSort);
        return flashSaleSkuMapper.selectPage(page, query);
    }

    @Override
    public List<FlashSaleSku> findList(FlashSaleSku params) {
        LambdaQueryWrapper<FlashSaleSku> query = Wrappers.lambdaQuery(FlashSaleSku.class);
        return flashSaleSkuMapper.selectList(query);
    }

    @Override
    public FlashSaleSku findById(Long id) {
        return flashSaleSkuMapper.selectById(id);
    }

    @Override
    public boolean insert(FlashSaleSku flashSaleSku) {
        return save(flashSaleSku);
    }

    @Override
    public boolean update(FlashSaleSku flashSaleSku) {
        return updateById(flashSaleSku);
    }

    @Override
    public int delete(Long id) {
        return flashSaleSkuMapper.deleteById(id);
    }

    @Override
    public void upFlashSkuSession(String sessionId) {
//        查询场次信息
        FlashSales flashSales = flashSalesService.getById(sessionId);
        String s = JSON.toJSONString(flashSales);
        String key = TimeUtils.convertLocalTimeToLong(flashSales.getStartTime()) + "_" + TimeUtils.convertLocalTimeToLong(flashSales.getEndTime());
//        存储场次信息
        redisTemplate.opsForValue().set(SESSION_PREFIX + key, s);
//      获取sku信息，存入缓存中
        List<FlashSaleSkuModel> skus = baseMapper.selectFlashSkusBySession(sessionId);
//        将场次ID作为这个场次下的sku的上级目录
        String sessionKey = SKU_PREFIX + sessionId + ":";
        for (FlashSaleSkuModel flashSaleSkuModel : skus) {
            log.info("存储信息{}", flashSaleSkuModel);
            String sku = JSON.toJSONString(flashSaleSkuModel);
            //      生成一个随机码，并将这个随机码存入，防止有人知道了skuId，然后恶心攻击接口
            UUID uuid = UUID.randomUUID();
            HashMap<String, String> stringStringHashMap = new HashMap<>();
            stringStringHashMap.put("token", uuid.toString());
            stringStringHashMap.put("sku", sku);
            stringStringHashMap.put("hasStock", flashSaleSkuModel.getStock().toString());
            stringStringHashMap.put("sold", "0");
            redisTemplate.opsForHash().putAll(sessionKey + flashSaleSkuModel.getSkuId(), stringStringHashMap);
        }
    }

    @Override
    public List<FlashSales> getCurrentFlashSaleSession() {
//        Long time = TimeUtils.convertLocalTimeToLong(LocalDateTime.now());
        long nowTime = new Date().getTime();
        //查询redis中所有的场次
        Set<String> keys = redisTemplate.keys(SESSION_PREFIX + "*");
        List<FlashSales> flashSalesArrayList = new ArrayList<>();
        if (keys != null && keys.size() > 0) {
            for (String key : keys) {
//            获取的key具有前缀:"flashSku:sessions:"，将前缀替换为空串
                String replace = key.replace(SESSION_PREFIX, "");
                String[] s = replace.split("_");
//                得到秒杀场次的起止时间
                long startTime = Long.parseLong(s[0]);
                long endTime = Long.parseLong(s[1]);
//                筛选出已经开启但是还没有结束的秒杀场次
                if (nowTime >= startTime && nowTime <= endTime) {
                    String flashSessionStr = (String) redisTemplate.opsForValue().get(key);
                    FlashSales flashSales = JSON.parseObject(flashSessionStr, FlashSales.class);
                    flashSalesArrayList.add(flashSales);
                }
                Instant instant1 = Instant.ofEpochMilli(nowTime);
                Instant instant2 = Instant.ofEpochMilli(startTime);
//                    时间差
                long durationInMillis = instant1.toEpochMilli() - instant2.toEpochMilli();
                long threeDaysInMillis = Duration.ofHours(72).toMillis();
                //  筛选出开启时间在三天之内（72小时）的秒杀场次
                if (nowTime <= startTime && durationInMillis <= threeDaysInMillis) {
                    String flashSessionStr = (String) redisTemplate.opsForValue().get(key);
                    FlashSales flashSales = JSON.parseObject(flashSessionStr, FlashSales.class);
                    flashSalesArrayList.add(flashSales);
                }
            }
        }
        return flashSalesArrayList;
    }

    @Override
    public List<FlashSaleSkuModel> getFlashSaleSkuModelBySessionId(String sessionId) {
        Set<String> skuKeys = redisTemplate.keys(SKU_PREFIX + sessionId + ":*");
        List<FlashSaleSkuModel> collect = null;
        if (skuKeys != null && skuKeys.size() > 0) {
            collect = skuKeys.stream().map(skuKey -> {
                String sku = (String) redisTemplate.opsForHash().get(skuKey, "sku");
                if (!StrUtil.isBlank(sku)) {
                    FlashSaleSkuModel skuModel = JSON.parseObject(sku, FlashSaleSkuModel.class);
                    int sold = Integer.parseInt((String) Objects.requireNonNull(redisTemplate.opsForHash().get(skuKey, "sold")));
                    int hasStock = Integer.parseInt(Objects.requireNonNull(redisTemplate.opsForHash().get(skuKey, "hasStock")).toString());
                    skuModel.setSoldPercentage(((sold / (sold + hasStock)) * 100));//已经售出的百分比
                    return skuModel;
                }
                return null;
            }).collect(Collectors.toList());
        }
        return collect;
    }

    @Override
    public FlashSaleSkuInfoVO getFlashSkuBySkuId(String skuId) {
//        如果不存在就返回空
        FlashSaleSkuInfoVO infoVO = null;
        List<FlashSales> currentFlashSaleSession = getCurrentFlashSaleSession();
        if (currentFlashSaleSession == null) {
            return null;
        }
        for (FlashSales flashSales : currentFlashSaleSession) {
//            查询这个场次下的sku
            List<FlashSaleSkuModel> flashSaleSkuModelBySessionId = getFlashSaleSkuModelBySessionId(flashSales.getId().toString());
            if (flashSaleSkuModelBySessionId != null) {
                String sessionKey = SKU_PREFIX + flashSales.getId() + ":";
                for (FlashSaleSkuModel skuModel : flashSaleSkuModelBySessionId) {
                    if (skuId.equals(skuModel.getSkuId())) {
                        infoVO = new FlashSaleSkuInfoVO();
                        LocalDateTime now = LocalDateTime.now();
                        if (flashSales.getStartTime().isBefore(now)) {
                            //       说明当前sku正在投入秒杀,取出这个sku的随机值,否则就是还未开启的秒杀场次，不返回token
                            String token = (String) redisTemplate.opsForHash().get(sessionKey + skuId, "token");
                            infoVO.setToken(token);
                        }
                        infoVO.setStartTime(flashSales.getStartTime());
                        infoVO.setEndTime(flashSales.getEndTime());
                        infoVO.setPrice(skuModel.getSalePrice());
                    }
                }
            }
        }
        return infoVO;
    }

    private String getSkuPath(String skuId) {
        //        如果不存在就返回空
        FlashSaleSkuInfoVO infoVO = null;
        List<FlashSales> currentFlashSaleSession = getCurrentFlashSaleSession();
        if (currentFlashSaleSession == null) {
            return null;
        }
        for (FlashSales flashSales : currentFlashSaleSession) {
//            查询这个场次下的sku
            List<FlashSaleSkuModel> flashSaleSkuModelBySessionId = getFlashSaleSkuModelBySessionId(flashSales.getId().toString());
            if (flashSaleSkuModelBySessionId != null) {
                String sessionKey = SKU_PREFIX + flashSales.getId() + ":";
                for (FlashSaleSkuModel skuModel : flashSaleSkuModelBySessionId) {
                    if (skuId.equals(skuModel.getSkuId())) {
                        return sessionKey + skuId;
                    }
                }
            }
        }
        return null;
    }

    @Override
    public BigDecimal buyFlashSaleSku(String skuId, Integer buyNumber, String skuToken) {
//        查询sku的信息并验证token
        FlashSaleSkuInfoVO flashSkuBySkuId = getFlashSkuBySkuId(skuId);
        if (flashSkuBySkuId == null) {
            return null;
        }
        if (LocalDateTime.now().isAfter(flashSkuBySkuId.getStartTime()) && LocalDateTime.now().isBefore(flashSkuBySkuId.getEndTime()) && skuToken.equals(flashSkuBySkuId.getToken())) {
            String skuPath = getSkuPath(skuId);
            if (skuPath != null) {
                Integer stock = Integer.valueOf(Objects.requireNonNull(redisTemplate.opsForHash().get(skuPath, "hasStock")).toString());
                //                如果购买数量超出库存，那么返回失败
                if (stock > buyNumber) {
                    redisTemplate.opsForHash().put(skuPath, "hasStock", stock - buyNumber);
                    return flashSkuBySkuId.getPrice();
                }
            }
        }
        return null;
    }
}
